﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using grounding.parser;

namespace BayesFileParser
{
    public enum CategoryName
    {
        AWAKE = 1,
        TIRED = -1,
        BALANCING = 2,
        FALLING = -2,
        CARRIED = 3,
        NOT_CARRIED = -3,
        COLD = 4,
        HOT = -4,
        DARK_ROOM = 5,
        LIGHT_ROOM = -5,
        LOOK_AT_FACE = 6,
        LOOK_AT_OBJECT = -6,
        HEAVY_WEIGHT = 7,
        LIGHT_WEIGHT = -7,
        MOVING = 8,
        STATIONARY = -8,
        NEAR = 9,
        FAR = -9,
        AFFECTION = 10,

        NONE = 0 // no category
    }

    // DO NOT CHANGE THE ORDER OF THESE VALUES OR REMOVE/ADD ANY.
    // The file parser matches these categories up to the values in
    // our CSV data files. If anything is changed, it will crash. ):
    public enum MetaCategoryName
    {
        TIREDNESS = 1,
        AFFECTION,   // we might ignore this
        STABILITY,
        GROUNDED,
        TEMPERATURE,
        BRIGHTNESS,
        LOOK_AT,
        WEIGHT,
        MOTION,
        DISTANCE
        
    }

    public class Category : ILogicElement
    {
        private static readonly Dictionary<CategoryName, Category> nameToCategoryDict = createNameToCategoryDictionary();
        private static readonly Dictionary<MetaCategoryName, CategoryPair> metaCategoryNameToCategoryPair = createCategoryPairDict();

        public static Dictionary<CategoryName, Category> CategoryNameToCategoryDictionary {
            get { return nameToCategoryDict; }
        }

        public static Dictionary<MetaCategoryName, CategoryPair> MetaCategoryNameToCategoryPair {
            get { return metaCategoryNameToCategoryPair; }
        }

        #region Setup
        private static Dictionary<CategoryName, Category> createNameToCategoryDictionary()
        {
            Dictionary<CategoryName, Category> dict = new Dictionary<CategoryName, Category>();

            dict.Add(CategoryName.AWAKE,
                new Category("Awake", CategoryName.AWAKE, CategoryName.TIRED, MetaCategoryName.TIREDNESS));
            dict.Add(CategoryName.TIRED,
                new Category("Tired", CategoryName.TIRED, CategoryName.AWAKE, MetaCategoryName.TIREDNESS));

            dict.Add(CategoryName.BALANCING,
                new Category("Balancing", CategoryName.BALANCING, CategoryName.FALLING, MetaCategoryName.STABILITY));
            dict.Add(CategoryName.FALLING,
                new Category("Falling", CategoryName.FALLING, CategoryName.BALANCING, MetaCategoryName.STABILITY));

            dict.Add(CategoryName.CARRIED,
                new Category("Carried", CategoryName.CARRIED, CategoryName.NOT_CARRIED, MetaCategoryName.GROUNDED));
            dict.Add(CategoryName.NOT_CARRIED,
                new Category("Not carried", CategoryName.NOT_CARRIED, CategoryName.CARRIED, MetaCategoryName.GROUNDED));

            dict.Add(CategoryName.COLD,
                new Category("Cold", CategoryName.COLD, CategoryName.HOT, MetaCategoryName.TEMPERATURE));
            dict.Add(CategoryName.HOT,
                new Category("Hot", CategoryName.HOT, CategoryName.COLD, MetaCategoryName.TEMPERATURE));

            dict.Add(CategoryName.DARK_ROOM,
                new Category("Dark room", CategoryName.DARK_ROOM, CategoryName.LIGHT_ROOM, MetaCategoryName.BRIGHTNESS));
            dict.Add(CategoryName.LIGHT_ROOM,
                new Category("Light room", CategoryName.LIGHT_ROOM, CategoryName.DARK_ROOM, MetaCategoryName.BRIGHTNESS));

            dict.Add(CategoryName.LOOK_AT_FACE,
                new Category("Look at face", CategoryName.LOOK_AT_FACE, CategoryName.LOOK_AT_OBJECT, MetaCategoryName.LOOK_AT));
            dict.Add(CategoryName.LOOK_AT_OBJECT,
                new Category("Look at object", CategoryName.LOOK_AT_OBJECT, CategoryName.LOOK_AT_FACE, MetaCategoryName.LOOK_AT));

            dict.Add(CategoryName.HEAVY_WEIGHT,
                new Category("Heavy weight", CategoryName.HEAVY_WEIGHT, CategoryName.LIGHT_WEIGHT, MetaCategoryName.WEIGHT));
            dict.Add(CategoryName.LIGHT_WEIGHT,
                new Category("Light weight", CategoryName.LIGHT_WEIGHT, CategoryName.HEAVY_WEIGHT, MetaCategoryName.WEIGHT));

            dict.Add(CategoryName.MOVING,
                new Category("Moving", CategoryName.MOVING, CategoryName.STATIONARY, MetaCategoryName.MOTION));
            dict.Add(CategoryName.STATIONARY,
                new Category("Stationary", CategoryName.STATIONARY, CategoryName.MOVING, MetaCategoryName.MOTION));

            dict.Add(CategoryName.NEAR,
                new Category("Near", CategoryName.NEAR, CategoryName.FAR, MetaCategoryName.DISTANCE));
            dict.Add(CategoryName.FAR,
                new Category("Far", CategoryName.FAR, CategoryName.NEAR, MetaCategoryName.DISTANCE));

            dict.Add(CategoryName.AFFECTION,
                new Category("Affection", CategoryName.AFFECTION, CategoryName.NONE, MetaCategoryName.AFFECTION));

            return dict;
        }

        public class CategoryPair
        {
            public Category first, second;

            public CategoryPair(Category first, Category second)
            {
                this.first = first;
                this.second = second;
            }
        }

        private static Dictionary<MetaCategoryName, CategoryPair> createCategoryPairDict()
        {
            Dictionary<MetaCategoryName, CategoryPair> pairs = new Dictionary<MetaCategoryName, CategoryPair>();

            pairs.Add(MetaCategoryName.TIREDNESS, new CategoryPair(
                nameToCategoryDict[CategoryName.AWAKE],
                nameToCategoryDict[CategoryName.TIRED]));
            pairs.Add(MetaCategoryName.AFFECTION, new CategoryPair(
                nameToCategoryDict[CategoryName.AFFECTION],
                null));
            pairs.Add(MetaCategoryName.STABILITY, new CategoryPair(
                nameToCategoryDict[CategoryName.BALANCING],
                nameToCategoryDict[CategoryName.FALLING]));
            pairs.Add(MetaCategoryName.GROUNDED, new CategoryPair(
                nameToCategoryDict[CategoryName.CARRIED],
                nameToCategoryDict[CategoryName.NOT_CARRIED]));
            pairs.Add(MetaCategoryName.TEMPERATURE, new CategoryPair(
                nameToCategoryDict[CategoryName.COLD],
                nameToCategoryDict[CategoryName.HOT]));
            pairs.Add(MetaCategoryName.BRIGHTNESS, new CategoryPair(
                nameToCategoryDict[CategoryName.DARK_ROOM],
                nameToCategoryDict[CategoryName.LIGHT_ROOM]));
            pairs.Add(MetaCategoryName.LOOK_AT, new CategoryPair(
                nameToCategoryDict[CategoryName.LOOK_AT_FACE],
                nameToCategoryDict[CategoryName.LOOK_AT_OBJECT]));
            pairs.Add(MetaCategoryName.WEIGHT, new CategoryPair(
                nameToCategoryDict[CategoryName.HEAVY_WEIGHT],
                nameToCategoryDict[CategoryName.LIGHT_WEIGHT]));
            pairs.Add(MetaCategoryName.MOTION, new CategoryPair(
                nameToCategoryDict[CategoryName.MOVING],
                nameToCategoryDict[CategoryName.STATIONARY]));
            pairs.Add(MetaCategoryName.DISTANCE, new CategoryPair(
                nameToCategoryDict[CategoryName.NEAR],
                nameToCategoryDict[CategoryName.FAR]));

            return pairs;
        }

        #endregion

        /// <summary>
        /// The order that the questions are read in the file, starting with 0
        /// </summary>
        private MetaCategoryName metaCategory;
        private string prettyPrintName;
        private CategoryName name;
        private CategoryName antonym;

        private Category(string prettyPrintName, CategoryName name, CategoryName antonym, MetaCategoryName metaCategory)
        {
            this.metaCategory = metaCategory;
            this.name = name;
            this.antonym = antonym;
            this.prettyPrintName = prettyPrintName;
        }

        #region Properties

        public CategoryName Name { get { return this.name; } }

        public CategoryName OppositeCategory { get { return this.antonym; } }

        public MetaCategoryName MetaCategory { get { return this.metaCategory; } }

        // old:
        public string Element { get { return prettyPrintName; } }

        #endregion

        #region ILogicElement Members


        public int Identifier
        {
            get { throw new NotImplementedException(); }
        }

        #endregion
    }
}